/*
 * Copyright 2011 Sriseshaa Technologies
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.sriseshaa.struts2.spring.interceptor;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import javax.servlet.ServletContext;

import org.springframework.context.ApplicationContext;
import org.springframework.web.context.WebApplicationContext;

import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionInvocation;
import com.opensymphony.xwork2.inject.Inject;
import com.opensymphony.xwork2.interceptor.AbstractInterceptor;
import com.opensymphony.xwork2.util.logging.Logger;
import com.opensymphony.xwork2.util.logging.LoggerFactory;
import com.sriseshaa.struts2.spring.SpringBeanInject;
import com.sriseshaa.struts2.spring.annotation.InjectBean;
import com.sriseshaa.struts2.spring.cache.AnnotatedField;
import com.sriseshaa.struts2.spring.cache.InjectBeanCache;
/**
  * @author Arunkumar Subramaniam
 */
public class SpringBusinessDelegate extends AbstractInterceptor {
	private static final long serialVersionUID = 1L;
	private static final Logger LOG = LoggerFactory.getLogger(SpringBusinessDelegate.class);

	@Inject ServletContext servletContext;	    
    private  InjectBeanCache cache;
    
    public SpringBusinessDelegate() {
    	cache=InjectBeanCache.getInstance();
	}
    
	@Override
	public void init() {		
		ApplicationContext rootWebApplicationContext =  (ApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

		 if (rootWebApplicationContext == null) {
	           
	            String message = "**********  ERROR INITILIZING SPRING CONTEXT **********\n" +
	                    "You might need to add the following to web.xml: \n" +
	                    "    <listener>\n" +
	                    "        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>\n" +
	                    "    </listener>";
	            LOG.error(message);	            
	       }	
	}

	@Override
	public String intercept(ActionInvocation actInv) throws Exception {
		ApplicationContext rootWebApplicationContext =  (ApplicationContext) servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
		SpringBeanInject beanInject;
		Object object=actInv.getAction();	
		String actionClassName=object.getClass().getName();
		Boolean hasBeanAnnotation= cache.hasInjectBeanAnnotations(actionClassName);
		
		//getting annotated fields from cache 
		if(Boolean.TRUE.equals(hasBeanAnnotation)){
		    beanInject=new SpringBeanInject(rootWebApplicationContext);
			List<AnnotatedField> annoFields = this.cache.getAnnotatedFields(object.getClass().getName());
			for (Iterator<AnnotatedField> itAnno = annoFields.iterator(); itAnno.hasNext();) {
				beanInject.injectBean((Action) object, itAnno.next());
			}
			
		}else if(hasBeanAnnotation==null){
			// create cache for annotated fields
			beanInject=new SpringBeanInject(rootWebApplicationContext);		
			List<AnnotatedField> annotatedFields = new ArrayList<AnnotatedField>();
			for (Field f : object.getClass().getDeclaredFields()) {
				if (f.isAnnotationPresent(InjectBean.class)) {					
					InjectBean annoObject=	 f.getAnnotation(InjectBean.class);				
					AnnotatedField annoFields = new AnnotatedField(annoObject, f);					
					annotatedFields.add(annoFields);
					beanInject.injectBean((Action) object,annoFields);
				}
			}
			
			//cache annotated fields
			if (annotatedFields.size() == 0) {
				cache.skipInjectBeanAnnotations(actionClassName);
			}
			else {
				cache.cacheAnnotatedFields(actionClassName, annotatedFields);
			}
		}
		
		
		return actInv.invoke();
	}



	
	
}
